using System;
using System.IO;
using System.Collections.Generic;
using Subsync.Core.Subversion;
using System.Diagnostics;

namespace Subsync.Core.Sync
{
	/// <summary>
	/// Author: Steven Goh Jian Wen, except the methods with Author: Hoang Duc
	/// </summary>
	public enum SyncType
	{
		Local,
		Network
	}

	public class Sync
	{
		//Class Properties
        public bool gui { get; set; }
        public string name { get; set; }
        public string description { get; set; }
        public string repo_url { get; set; }
        public string working_copy_path { get; set; }
        public string def_repos_dir { get; set; }
        public bool hosted { get; set; }
        public bool auto_conflict_management { get; set; }
        public string icon { get; set; }
        public string last_sync { get; set; }

		//gui conflict management
        public List<Dictionary<string, string>> conflicts { get; set; }
		private string temp_working_copy_path;

		public delegate void GuiConflictManagement (object source, Sync s);
		public event GuiConflictManagement GuiConflict;

		void OnGuiConflict (Sync s)
		{
			if (GuiConflict != null)
				GuiConflict (this, s);
		}

		//------- SYNC Instantiation -------//
		/// <summary>
		/// Empty constructor for manual construction.
		/// 
		/// Done by Steven Goh Jian Wen
		/// </summary>
		public Sync ()
		{
            this.description = "No Description";
            this.icon = Path.Combine(new Config().GetProperty("ImageStoragePath"), "fdrorange.png");
		}

		public Sync (string name, string repo_url, string working_copy_path, bool auto_manage_conflicts, bool hosted)
		{
			this.description = "No Description";
			this.icon = Path.Combine (new Config ().GetProperty ("ImageStoragePath"), "fdrorange.png");
			this.name = name;
			this.repo_url = repo_url;
			this.working_copy_path = working_copy_path;
			this.auto_conflict_management = auto_manage_conflicts;
			this.hosted = hosted;
		}
		
		public bool IsRepoValid ()
		{
			try
            {
				new SVNInfo (this.repo_url, "head", "head").Execute ();
			}
            catch (Exception)
            {
				return false;
			}
			return true;
		}

		/// <summary>
		/// Done by Steven Goh Jian Wen 
		/// </summary>
		public void Execute ()
		{
			//check if repos is valid
			try
            {
				new SVNInfo (this.repo_url, "head", "head").Execute ();
			}
            catch (Exception e)
            {
				throw new RepositoryNotFound (e.Message);
			}
			
			//protocol checking
			string protocol = this.repo_url;
			bool fileProtocol = AllowedProtocol (protocol);
			
			SVNStatus.status_of_all_wc_files.Clear ();
			Debug.WriteLine ("Updating files' statuses");
			Dictionary<string, string> fileStatuses = SVNStatus.SVNStatusAll (this.working_copy_path, true);
			
			foreach (KeyValuePair<string, string> fileStatus in fileStatuses) {
				if (fileStatus.Value.Equals ("?")) {
					string filePath = fileStatus.Key;
					if (File.Equals (new java.io.File (filePath), new java.io.File (working_copy_path)))
						continue;
					ClearVersionControl (filePath);
				}
			}
			
			//doing a preemptive cleanup
			new SVNCleanup (this.working_copy_path).Execute ();

			
			Debug.WriteLine ("Syncing {0}: Updating", this.name);
            try
            {
                new SVNUpdate(this.working_copy_path).Execute();
            }
            catch (IOException)
            {
                throw new DiskSpaceException("Not enough disk space");
            }

            Debug.WriteLine("Syncing {0}: Adding", this.name);
            if (fileProtocol)
                new SVNAdd(this.working_copy_path, true).Execute();


            foreach (KeyValuePair<string, string> fileStatus in fileStatuses) {
				if (fileStatus.Value.Equals ("!") || fileStatus.Value.Equals ("D")) {
					string filePath = fileStatus.Key;
					if (File.Equals (new java.io.File (filePath), new java.io.File (working_copy_path)))
						continue;
					new SVNRemove (filePath).Execute ();
				}
			}
			
			Debug.WriteLine ("Syncing {0}: Conflict Management", this.name);
			List<string> conflicted_files = GetConflictedFiles (this.working_copy_path);
            this.conflicts = new List<Dictionary<string, string>>();
            foreach (string f in conflicted_files)
            {
                this.conflicts.Add(new Dictionary<string, string> { {"", f} });
            }

            if (!gui)
            {
                foreach (string f in conflicted_files)
                {
                    if (auto_conflict_management)
                    {
                        new SVNResolve(f, Resolution.MineFully).Execute();
                    }
                    else
                    {
                        //manual management
                        Resolution response = PromptConflictResolution(f);
                        new SVNResolve(f, response).Execute();
                    }
                }
            }
            else
            {
                if (auto_conflict_management)
                {
                    foreach (string f in conflicted_files) 
                    {
                        new SVNResolve(f, Resolution.MineFully).Execute();
                    }
                }
                else if (conflicted_files.Count > 0)
                {
                    OnGuiConflict(this);
                    return;
                }
            }

			
			Debug.WriteLine ("Syncing {0}: SVNCommit", this.name);
			if (fileProtocol)
                try
                {
                    new SVNCommit(this.working_copy_path).Execute();
                }
                catch (IOException)
                {
                    throw new DiskSpaceException("Not enough disk space");
                }
			
			this.last_sync = System.DateTime.Now.ToString ();
			new Subsync.Core.Sync.Config ().SetSyncProperty (this, "LastSync", System.DateTime.Now.ToString ());
		}

		//------- SYN Creation -------//

		public void NewSync (string def_repos_path)
		{
			if (!PathExists (this.working_copy_path))
				throw new FolderDoesNotExist (this.working_copy_path);
			
			List<Sync> existingWCs = new Config ().GetAllSyncs ();
			foreach (Sync wc in existingWCs) {
				if (wc.working_copy_path == this.working_copy_path) {
					throw new PathAlreadyAWorkingCopy (this.working_copy_path + " is already a working copy");
				}
			}
			
			ClearVersionControl (this.working_copy_path);
			
			this.hosted = true;
			
			string final_repo_path = "";
			string final_repo_url = "";
			
			if (!PathExists (Path.Combine (def_repos_path, this.working_copy_path.Substring (this.working_copy_path.LastIndexOf (Path.DirectorySeparatorChar) + 1))))
				final_repo_path = Path.Combine (def_repos_path, this.working_copy_path.Substring (this.working_copy_path.LastIndexOf (Path.DirectorySeparatorChar) + 1));
			else {
				final_repo_path = Path.Combine (def_repos_path, Tools.RandomStr ());
				while (PathExists (final_repo_path)) {
					final_repo_path = Path.Combine (def_repos_path, Tools.RandomStr ());
				}
			}
			
			final_repo_url = "file://" + final_repo_path.Replace (Path.DirectorySeparatorChar, '/');
			this.repo_url = final_repo_url;

            try
            {
                Debug.WriteLine("NewSync: Creating repository on {0}", final_repo_path);
                new SVNAdminCreate(final_repo_path).Execute();

                Debug.WriteLine("NewSync: Performing SVN import");
                new SVNImport(this.working_copy_path, final_repo_url).Execute();
            }
            catch (IOException)
            {
                throw new DiskSpaceException("Not enough disk space");
            }
			
			Debug.WriteLine ("NewSync: Deleting original directory");
			DeleteDirectory (this.working_copy_path);
			
			Debug.WriteLine ("NewSync: Performing SVNCheckout to create working path");
            try
            {
                new SVNCheckout(final_repo_url, this.working_copy_path).Execute();
            }
            catch (IOException)
            {
                throw new DiskSpaceException("Not enough disk space");
            }
			
			Debug.WriteLine ("NewSync: Writing to config file");
			new Config ().SaveSync (this);
		}

		public void NewSync ()
		{
			string def_repos_path = new Config ().GetProperty ("RepoStoragePath");
			NewSync (def_repos_path);
		}

		[System.Obsolete("use non-static function")]
		public static Sync NewSync (string sync_name, string path_to_folder, bool auto_manage_conflicts, string custom_repo_dir)
		{
			List<Sync> existingWCs = new Config ().GetAllSyncs ();
			foreach (Sync wc in existingWCs) {
				if (wc.working_copy_path == path_to_folder) {
					throw new PathAlreadyAWorkingCopy (path_to_folder + " is already a working copy");
				}
			}
			
			Debug.WriteLine ("Sync: Creating new sync");
			string final_repo_path = "";
			string final_repo_url = "";
			string def_repos_path = "";
			if (custom_repo_dir == "")
				def_repos_path = new Config ().GetProperty ("RepoStoragePath");
			else
				def_repos_path = custom_repo_dir;
			
			if (!PathExists (Path.Combine (def_repos_path, path_to_folder.Substring (path_to_folder.LastIndexOf (Path.DirectorySeparatorChar) + 1))))
				final_repo_path = Path.Combine (def_repos_path, path_to_folder.Substring (path_to_folder.LastIndexOf (Path.DirectorySeparatorChar) + 1));
			else {
				final_repo_path = Path.Combine (def_repos_path, Tools.RandomStr ());
				while (PathExists (final_repo_path)) {
					final_repo_path = Path.Combine (def_repos_path, Tools.RandomStr ());
				}
			}
			
			final_repo_url = "file://" + final_repo_path.Replace (Path.DirectorySeparatorChar, '/');
			
			if (!PathExists (path_to_folder))
				throw new FolderDoesNotExist (path_to_folder);
			
			Debug.WriteLine ("NewSync: Creating repository on {0}", final_repo_path);
			SVNAdminCreate create_obj = new SVNAdminCreate (final_repo_path);
			create_obj.Execute ();
			
			Debug.WriteLine ("NewSync: Performing SVN import");
			new SVNImport (path_to_folder, final_repo_url).Execute ();
			
			Debug.WriteLine ("NewSync: Deleting original directory");
			Directory.Delete (path_to_folder, true);
			
			Debug.WriteLine ("NewSync: Performing SVNCheckout to create working path");
			new SVNCheckout (final_repo_url, path_to_folder).Execute ();
			
			Debug.WriteLine ("NewSync: Writing to config file");
			Sync s = new Sync (sync_name, final_repo_url, path_to_folder, auto_manage_conflicts, true);
			new Config ().SaveSync (s);
			
			return s;
		}

		[System.Obsolete("use non-static function")]
		public static Sync NewSync (string sync_name, string path_to_folder, bool auto_manage_conflicts)
		{
			return NewSync (sync_name, path_to_folder, auto_manage_conflicts, "");
		}

		public Sync AddSync (SyncType type, string sync_name, string new_sync_name, string path_to_folder, string network_repo_url, bool auto_manage_conflicts)
		{
			this.name = new_sync_name;
			this.working_copy_path = path_to_folder;
			this.auto_conflict_management = auto_manage_conflicts;
			this.hosted = false;
			
			List<Sync> existingWCs = new Config ().GetAllSyncs ();
			foreach (Sync s in existingWCs) {
				if (s.working_copy_path == path_to_folder) {
					throw new PathAlreadyAWorkingCopy (path_to_folder + " is already a working copy");
				}
			}
			
			Debug.WriteLine ("addSync: Adding a new sync");
			string repo_url = "";
			this.def_repos_dir = new Config ().GetProperty ("RepoStoragePath");
			
			temp_working_copy_path = GetRandomPath (def_repos_dir);
			
			if (type == SyncType.Local) {
				//repo_url
				if (!SyncExists (sync_name))
					throw new SyncNotFound (sync_name);
				else
					repo_url = GetSyncRepoURL (sync_name);
			} else if (type == SyncType.Network) {
				repo_url = network_repo_url;
			}
			this.repo_url = repo_url;
			
			//manage conflicts and create working copy
			if (PathExists (path_to_folder)) {
				Debug.WriteLine ("addSync: Path exists, converting it to a working copy");
				Debug.WriteLine ("addSync: Checking out to a temp path");
                try
                {
                    new SVNCheckout(repo_url, temp_working_copy_path).Execute();
                }
                catch (IOException)
                {
                    throw new DiskSpaceException("Not enough disk space");
                }
				
				Debug.WriteLine ("addSync: Beginning conflict management");
				//begin conflict management
				List<Dictionary<string, string>> conflicted_files = MoveFilter (path_to_folder, temp_working_copy_path, auto_manage_conflicts);
				this.conflicts = conflicted_files;
				if (!gui) {
					foreach (Dictionary<string, string> conflicted in conflicted_files) {
						switch (PromptConflictResolution (conflicted["versioned"])) {
                            case Resolution.MineFully:
							    File.Delete (conflicted["versioned"]);
							    File.Move (conflicted["unversioned"], Path.Combine (Directory.GetParent (conflicted["versioned"]).ToString (), Path.GetFileName (conflicted["unversioned"])));
							    break;
						    case Resolution.TheirsFully:
							    //do nothing.
							    break;
						}
					}
				} else {
					if (conflicted_files.Count > 0) {
						OnGuiConflict (this);
						return this;
					}
				}
				
				Debug.WriteLine ("addSync: SVNAdd/SVNCommit");
				new SVNAdd (temp_working_copy_path, true).Execute ();
                try
                {
                    new SVNCommit(temp_working_copy_path).Execute();
                }
                catch (IOException)
                {
                    throw new DiskSpaceException("Not enough disk space");
                }
				
				Debug.WriteLine ("addSync: Directory Delete/Move");
				DeleteDirectory (path_to_folder);
				if (Path.GetPathRoot (temp_working_copy_path) == Path.GetPathRoot (path_to_folder))
					Directory.Move (temp_working_copy_path, path_to_folder);
				else {
                    try
                    {
                        Copy(temp_working_copy_path, path_to_folder);
                    }
                    catch (IOException)
                    {
                        throw new DiskSpaceException("Not enough disk space");
                    }
					DeleteDirectory (temp_working_copy_path);
				}
				
			} else {
				//checkout
				Debug.WriteLine ("addSync: Path does not exist, performing SVNCheckout");
                try
                {
                    new SVNCheckout(repo_url, path_to_folder).Execute();
                }
                catch (IOException)
                {
                    throw new DiskSpaceException("Not enough disk space");
                }
			}
			new Config ().SaveSync (this);
			return this;
		}


		public void ConflictCont ()
		{
			Debug.WriteLine ("addSync: SVNAdd/SVNCommit");
			new SVNAdd (temp_working_copy_path, true).Execute ();
			new SVNCommit (temp_working_copy_path).Execute ();
			
			Debug.WriteLine ("addSync: Directory Delete/Move");
			DeleteDirectory (this.working_copy_path);
			if (Path.GetPathRoot (temp_working_copy_path) == Path.GetPathRoot (this.working_copy_path))
				Directory.Move (temp_working_copy_path, this.working_copy_path);
			else {
				Copy (temp_working_copy_path, this.working_copy_path);
				DeleteDirectory (temp_working_copy_path);
			}
			
			Debug.WriteLine ("addSync: Writing to config");
			new Config ().SaveSync (this);
		}

		/// <summary>
		/// Author: Hoang Duc
		/// </summary>
        public void ConflictExecuteCont(List<String> doOverwrite)
        {
            if (doOverwrite.Count == 0)
            {
                foreach (Dictionary<string, string> c in this.conflicts)
                {
                    new SVNResolve(c[""], Resolution.TheirsFully).Execute();
                }
            }
            else
            {
                foreach (Dictionary<string, string> c in this.conflicts)
                {
                    foreach (string file in doOverwrite)
                    {
                        if (c[""] == file)
                        {
                            new SVNResolve(c[""], Resolution.MineFully).Execute();
                        }
                        else
                        {
                            new SVNResolve(c[""], Resolution.TheirsFully).Execute();
                        }
                    }
                }
            }

            string protocol = this.repo_url;
            bool fileProtocol = AllowedProtocol(protocol);

            Debug.WriteLine("Syncing {0}: SVNAdd/Commit", this.name);
            if (fileProtocol)
                try
                {
                    new SVNCommit(this.working_copy_path).Execute();
                }
                catch (IOException)
                {
                    throw new DiskSpaceException("Not enough disk space");
                }

            this.last_sync = System.DateTime.Now.ToString();
            new Subsync.Core.Sync.Config().SetSyncProperty(this, "LastSync", System.DateTime.Now.ToString());
        }

		/// <summary>
		/// Delete sync
		/// </summary>
		public void Remove ()
		{
			//remove from config file
			new Config ().DeleteSync (this);
			
			ClearVersionControl (this.working_copy_path);
			
			if (this.hosted) {
                List<Sync> syncs = new Config().GetAllSyncs();
                foreach (Sync s in syncs)
                {
                    if (s.name != this.name)
                        if (s.repo_url == this.repo_url) return;
                }
				//delete repo
				string path = this.repo_url.Remove (0, this.repo_url.IndexOf("//")+2);
				if (Directory.Exists (path))
					DeleteDirectory (path);
			}
			
		}

		//------- BACKUP TRANSVERSE BELOW -------//

		/// <summary>
		/// Author: Hoang Duc
		/// </summary>
		public void BackupTransverse (string working_copy_path, string revisionNumber)
		{
			this.working_copy_path = working_copy_path;
			try {
				new SVNRevert (new string[] { this.working_copy_path }).Execute ();
				new SVNUpdate (working_copy_path).Execute ();
				new SVNMerge (working_copy_path, "head", this.repo_url, revisionNumber).Execute ();
				//new SVNCommit(working_copy_path).Execute();
				
				SVNStatus.status_of_all_wc_files.Clear ();
				Debug.WriteLine ("Updating files' statuses");
				Dictionary<string, string> mergedFileStatuses = SVNStatus.SVNStatusAll (this.working_copy_path, true);
				foreach (KeyValuePair<string, string> fileStatus in mergedFileStatuses) {
					if (fileStatus.Value.Equals ("!") || fileStatus.Value.Equals ("D")) {
						string filePath = fileStatus.Key;
						if (File.Equals (new java.io.File (filePath), new java.io.File (working_copy_path)))
							continue;
						new SVNRemove (filePath).Execute ();
					}
				}
			} catch (Exception e) {
				throw new BackupTransverseException (e.Message);
			}
			
			Debug.WriteLine ("Updating files' statuses");
			Dictionary<string, string> fileStatuses;
			if (Directory.Exists (working_copy_path)) {
				SVNStatus.status_of_all_wc_files.Clear ();
				fileStatuses = SVNStatus.SVNStatusAll (this.working_copy_path, true);
				
				foreach (KeyValuePair<string, string> fileStatus in fileStatuses) {
					if (!fileStatus.Value.Equals (" "))
						Console.WriteLine (fileStatus.Value + " " + fileStatus.Key);
				}
			}
		}

		//------- SYNC HELPERS BELOW -------//

		/// <summary>
		/// Author: Hoang Duc
		/// Remove version control files.
		/// </summary>
		public void ClearVersionControl (string filePath)
		{
			if (!Directory.Exists (filePath)) {
				if (File.Exists (filePath) && filePath.Contains (".svn"))
					File.Delete (filePath);
				return;
			}
			string[] dirList = Directory.GetDirectories (filePath, "*", SearchOption.AllDirectories);
			foreach (string dir in dirList) {
				if (Directory.Exists (dir) && dir.Contains (".svn")) {
					DeleteDirectory (dir);
				}
			}
		}

		/// <summary>
		/// Author: Hoang Duc
		/// Delete a non-empty directory
		/// </summary>
		public static bool DeleteDirectory (string target_dir)
		{
			bool result = false;
			
			string[] files = Directory.GetFiles (target_dir);
			string[] dirs = Directory.GetDirectories (target_dir);
			
			foreach (string file in files) {
				File.SetAttributes (file, FileAttributes.Normal);
				File.Delete (file);
			}
			
			foreach (string dir in dirs) {
				DeleteDirectory (dir);
			}
			
			Directory.Delete (target_dir, false);
			
			return result;
		}

		/// <summary>
		/// Author: Hoang Duc
		///Copy directory
		/// </summary>
		public void Copy (string source, string destination)
		{
			if (!Directory.Exists (destination))
				Directory.CreateDirectory (destination);
			
			string[] files = Directory.GetFiles (source);
			
			foreach (string f in files) {
				string fileName = Path.GetFileName (f);
				string destFile = Path.Combine (destination, fileName);
				File.SetAttributes (f, FileAttributes.Normal);
				File.Copy (f, destFile, true);
			}
			
			string[] dirs = Directory.GetDirectories (source, "*", SearchOption.TopDirectoryOnly);
			
			foreach (string d in dirs) {
				string folderName = Path.GetFileName (d);
				string destFolder = Path.Combine (destination, folderName);
				Copy (d, destFolder);
			}
			
		}

		/// <summary>
		/// Author: Hoang Duc
		/// Protocol check
		/// </summary>
		public bool AllowedProtocol (string protocol)
		{
			string[] allowed = new string[] { "file://", "http://", "svn://", "https://" };
			foreach (string prot in allowed) {
				if (protocol.StartsWith (prot))
					return true;
			}
			return false;
		}

		/// <summary>
		/// Check if sync is written in config file.
		/// </summary>
		/// <param name="sync_name">
		/// A <see cref="System.String"/>
		/// </param>
		/// <returns>
		/// A <see cref="System.Boolean"/>
		/// </returns>
		public static bool SyncExists (string sync_name)
		{
			try {
				new Config ().LoadSync (sync_name);
			} catch (SyncNotFound) {
				return false;
			}
			return true;
			
		}

		/// <summary>
		/// Check if path exists
		/// </summary>
		/// <param name="path">
		/// A <see cref="System.String"/>
		/// </param>
		/// <returns>
		/// A <see cref="System.Boolean"/>
		/// </returns>
		public static bool PathExists (string path)
		{
			return Directory.Exists (path);
		}

		/// <summary>
		/// Build a random path name with base_path as parent.
		/// </summary>
		/// <param name="base_path">
		/// A <see cref="System.String"/>
		/// </param>
		/// <returns>
		/// A <see cref="System.String"/>
		/// </returns>
		public static string GetRandomPath (string base_path)
		{
			string random_path = Path.Combine (base_path, Tools.RandomStr ());
			
			if (PathExists (random_path))
				return GetRandomPath (base_path);
			return random_path;
		}

		public static List<Dictionary<string, string>> MoveFilter (string from_folder, string to_folder, bool manage_conflicts)
		{
			List<Dictionary<string, string>> ret = new List<Dictionary<string, string>> ();
			
			List<string> from_files = RecursiveFilesInDirectory (from_folder);
			foreach (string f in from_files) {
				
				string trimmed_f = f.Replace (from_folder, "");
				if (trimmed_f.Substring (0, 1) == Path.DirectorySeparatorChar.ToString ())
					trimmed_f = trimmed_f.Substring (1, trimmed_f.Length - 1);
				string appended_t = CrossPlatformPath (Path.Combine (to_folder, trimmed_f));
				
				if (File.Exists (appended_t)) {
					//conflict matched
					if (!manage_conflicts) {
						//Console.WriteLine ("Manually adding");
						ret.Add (new Dictionary<string, string> { { "versioned", appended_t }, { "unversioned", f } });
					} else {
						//auto manage
						//Console.WriteLine ("Auto managing conflicts");
						File.Delete (appended_t);
						File.Move (f, appended_t);
						//Console.WriteLine ("Moving {0} to {1}", f, appended_t);
					}
				} else {
					//Console.WriteLine ("Moving {0} to {1}", f, appended_t);
					FileMove (f, appended_t);
				}
			}
			return ret;
		}

		public static List<string> RecursiveFilesInDirectory (string from_folder)
		{
			List<string> ret = new List<string> ();
			string[] subfolders = Directory.GetDirectories (from_folder);
			
			foreach (string f in subfolders) {
				if (f.Substring (f.LastIndexOf (Path.DirectorySeparatorChar) + 1) != ".svn")
					ret.AddRange (RecursiveFilesInDirectory (f));
			}
			
			foreach (string f in Directory.GetFiles (from_folder)) {
				ret.Add (f);
			}
			return ret;
		}

		/// <summary>
		/// Console prompt user for conflict management during sync addition
		/// </summary>
		/// <param name="versioned">
		/// A <see cref="System.String"/>
		/// </param>
		/// <param name="unversioned">
		/// A <see cref="System.String"/>
		/// </param>
		/// <returns>
		/// A <see cref="ConflictResolution"/>
		/// </returns>
		public static Resolution PromptConflictResolution (string versioned)
		{
			string response = "";
			while ((response != "1") && (response != "2")) {
				Console.WriteLine ("Do you want {0} to be kept (1) or use repository's copy? (2)", Path.GetFileName (versioned));
				response = Console.ReadLine ();
                if ((response != "1") && (response != "2"))
                    Console.WriteLine("Invalid choice.");
			}
			
			if (response == "1")
				return Resolution.MineFully;
            else
                return Resolution.TheirsFully;
		}

		/// <summary>
		/// Find all the files which are marked conflicted.
		/// </summary>
		/// <param name="path">
		/// A <see cref="System.String"/>
		/// </param>
		/// <returns>
		/// A <see cref="List<System.String>"/>
		/// </returns>
		public List<string> GetConflictedFiles (string path)
		{
			List<string> ret = new List<string> ();
			List<string> files = RecursiveFilesInDirectory (path);
			foreach (string f in files) {
				SVNStatus s = new SVNStatus (f);
                try
                {
                    s.Execute();
                    if (s.statusInfo.pathChangeType == "C")
                        ret.Add(f);
                }
                catch (Exception)
                {
                }				
			}
			return ret;
		}

		public static string CrossPlatformPath (string path)
		{
			char conflict = '/';
			if (Path.DirectorySeparatorChar.ToString () == "/")
				conflict = '\\';
			
			if (path.Contains (conflict.ToString ()))
				path = path.Replace (conflict, Path.DirectorySeparatorChar);
			
			return path;
		}

		public static void FileMove (string from_path, string to_path)
		{
			Directory.CreateDirectory (Directory.GetParent (to_path).ToString ());
			File.Move (from_path, to_path);
		}

		public static string GetSyncRepoURL (string sync_name)
		{
			return new Config ().LoadSync (sync_name).repo_url;
		}
	}
}
